package me.yricky.alia.ui.layoutPage

import androidx.compose.ui.graphics.Matrix
import kotlinx.coroutines.flow.MutableStateFlow
import me.yricky.alia.data.base.Coord
import me.yricky.alia.data.hierarchy.*
import me.yricky.alia.data.shape.*
import me.yricky.alia.ui.Wrapper
import me.yricky.alia.ui.layoutPage.renderModel.LayerRender
import me.yricky.alia.utils.filterInstanceAnd

/**
 * @author Yricky
 * @date 2022/2/6
 */
class CellCanvasViewModel {
    class ViewState(
        val cellBBox: MutableStateFlow<Box>,
        val invisibleLayer: MutableStateFlow<Wrapper<MutableSet<Layer.LDPair>>>,
        val showGridDots:MutableStateFlow<Boolean>,

        val offset: MutableStateFlow<Coord>,
        val zoom:MutableStateFlow<Float>,
    )
    val layerRenders:MutableList<LayerRender> = ArrayList()

    val viewState = ViewState(
        cellBBox = MutableStateFlow(defBox),
        invisibleLayer = MutableStateFlow( Wrapper(mutableSetOf())),
        showGridDots = MutableStateFlow(false),
        offset = MutableStateFlow( Coord(0,0) ),
        zoom = MutableStateFlow(1f)
    )

    fun setCell(cell:Cell,lib:Library){
        val bBox = cell.calcBBox
        viewState.cellBBox.value = bBox
        viewState.invisibleLayer.value = Wrapper(mutableSetOf())
        layerRenders.addAll(addCell(layerRenders.associateBy { it.layerId }.toMutableMap(),cell,lib, Matrix()).values.toList())
        setZoom(1f)
        setOffset(bBox.center)
    }

    fun addCell(layerMap: MutableMap<Layer.LDPair,LayerRender>, cell: Cell, library: Library, matrix: Matrix):MutableMap<Layer.LDPair,LayerRender>{
        var layers = layerMap
        val cells = library.cells.associateBy { it.name }
        cell.layers.forEach { cellLayer->
            (layers[cellLayer.id]?:LayerRender(
                layerId = cellLayer.id,
                style = LayerRender.LayerStyle.get(cellLayer.id),
                renderUnits = ArrayList()
            ).also {
                layers[cellLayer.id] = it
            }).renderUnits.add(
                let {
                    val (shapes,texts) = cellLayer.shapes.filterInstanceAnd<Shape, Text>()
                    Pair(cell,LayerRender.LayerRenderUnit(
                        cell,texts, shapes, matrix
                    ))
                }

            )
        }
        cell.cellRefs.flatMap {
            if(it is SingleCellRef)
                listOf(it)
            else if(it is ArrayCellRef){
                it.toCellRefs()
            }else{
                listOf()
            }
        }.forEach { ref->
            Matrix()
            cells[ref.name]?.let{
                layers = addCell(layers,it,library, Matrix().apply{
                    setFrom(matrix)
                    timesAssign(ref.transformMatrix)
                })
            }
        }
        return layers
    }


    fun toggleLayerVisibility(layer: Layer.LDPair){
        val set = viewState.invisibleLayer.value.value
        viewState.invisibleLayer.value = if(set.contains(layer)){
            set.remove(layer)
            Wrapper(set)
        }else{
            set.add(layer)
            Wrapper(set)
        }
    }

    //TODO 更新视图
    fun setLayerStyle(l:Layer.LDPair,style: LayerRender.LayerStyle){
        layerRenders.find {
            it.layerId == l
        }?.style = style
    }

    fun setZoom(zoom:Float){
        viewState.zoom.value = zoom
    }

    fun setOffset(offset: Coord){
        viewState.offset.value = offset
    }

    fun setShowGridDots(b:Boolean){
        viewState.showGridDots.value = b
    }
}